﻿using Caliburn.Micro;
using SD.Common;
using SD.Infrastructure.DTOBase;
using SD.Infrastructure.WPF.Caliburn.Aspects;
using SD.Infrastructure.WPF.Caliburn.Base;
using SD.Infrastructure.WPF.Extensions;
using SD.Infrastructure.WPF.Interfaces;
using SD.Infrastructure.WPF.Models;
using SD.IOC.Core.Mediators;
using SlamDunk.MES.Client.ViewModels.Facility;
using SlamDunk.MES.Client.ViewModels.ProductionPlan;
using SlamDunk.MES.IAppService.DTOs.Outputs.DefinitionContext;
using SlamDunk.MES.IAppService.DTOs.Outputs.PlanContext;
using SlamDunk.MES.IAppService.DTOs.Outputs.ResourceContext;
using SlamDunk.MES.IAppService.Interfaces;
using SlamDunk.ValueObjects.Enums;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.ServiceModel.Extensions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace SlamDunk.MES.Client.ViewModels.ExecutionTrack
{
    /// <summary>
    /// 作业跟踪首页视图模型
    /// </summary>
    public class IndexViewModel : ScreenBase, IPaginatable
    {
        #region # 字段及构造器

        /// <summary>
        /// 资源定义服务契约接口代理
        /// </summary>
        private readonly ServiceProxy<IResourceContract> _resourceContract;

        /// <summary>
        /// 产品定义服务契约接口代理
        /// </summary>
        private readonly ServiceProxy<IDefinitionContract> _definitionContract;

        /// <summary>
        /// 计划管理服务契约接口代理
        /// </summary>
        private readonly ServiceProxy<IPlanContract> _planContract;

        /// <summary>
        /// 窗口管理器
        /// </summary>
        private readonly IWindowManager _windowManager;

        /// <summary>
        /// 依赖注入构造器
        /// </summary>
        public IndexViewModel(ServiceProxy<IResourceContract> resourceContract, ServiceProxy<IDefinitionContract> definitionContract, ServiceProxy<IPlanContract> planContract, IWindowManager windowManager)
        {
            this._resourceContract = resourceContract;
            this._definitionContract = definitionContract;
            this._planContract = planContract;
            this._windowManager = windowManager;

            //默认值
            this.PageIndex = 1;
            this.PageSize = 20;
        }

        #endregion

        #region # 属性

        #region 关键字 —— string Keywords
        /// <summary>
        /// 关键字
        /// </summary>
        [DependencyProperty]
        public string Keywords { get; set; }
        #endregion

        #region 开始时间 —— DateTime? StartTime
        /// <summary>
        /// 开始时间
        /// </summary>
        [DependencyProperty]
        public DateTime? StartTime { get; set; }
        #endregion

        #region 结束时间 —— DateTime? EndTime
        /// <summary>
        /// 结束时间
        /// </summary>
        [DependencyProperty]
        public DateTime? EndTime { get; set; }
        #endregion

        #region 页码 —— int PageIndex
        /// <summary>
        /// 页码
        /// </summary>
        [DependencyProperty]
        public int PageIndex { get; set; }
        #endregion

        #region 页容量 —— int PageSize
        /// <summary>
        /// 页容量
        /// </summary>
        [DependencyProperty]
        public int PageSize { get; set; }
        #endregion

        #region 总记录数 —— int RowCount
        /// <summary>
        /// 总记录数
        /// </summary>
        [DependencyProperty]
        public int RowCount { get; set; }
        #endregion

        #region 总页数 —— int PageCount
        /// <summary>
        /// 总页数
        /// </summary>
        [DependencyProperty]
        public int PageCount { get; set; }
        #endregion

        #region 已选产品 —— MaterialInfo SelectedProduct
        /// <summary>
        /// 已选产品
        /// </summary>
        [DependencyProperty]
        public MaterialInfo SelectedProduct { get; set; }
        #endregion

        #region 已选工艺 —— ProcessInfo SelectedProcess
        /// <summary>
        /// 已选工艺
        /// </summary>
        [DependencyProperty]
        public ProcessInfo SelectedProcess { get; set; }
        #endregion

        #region 已选物料清单 —— BomInfo SelectedBom
        /// <summary>
        /// 已选物料清单
        /// </summary>
        [DependencyProperty]
        public BomInfo SelectedBom { get; set; }
        #endregion

        #region 已选计划状态 —— ExecutionPlanStatus? SelectedPlanStatus
        /// <summary>
        /// 已选计划状态
        /// </summary>
        [DependencyProperty]
        public ExecutionPlanStatus? SelectedPlanStatus { get; set; }
        #endregion

        #region 已选审核状态 —— CheckStatus? SelectedCheckStatus
        /// <summary>
        /// 已选审核状态
        /// </summary>
        [DependencyProperty]
        public CheckStatus? SelectedCheckStatus { get; set; }
        #endregion

        #region 已选生产计划 —— ProductionPlanInfo SelectedProductionPlan
        /// <summary>
        /// 已选生产计划
        /// </summary>
        [DependencyProperty]
        public ProductionPlanInfo SelectedProductionPlan { get; set; }
        #endregion

        #region 已选工厂模型 —— Node SelectedFacility
        /// <summary>
        /// 已选工厂模型
        /// </summary>
        [DependencyProperty]
        public Node SelectedFacility { get; set; }
        #endregion

        #region 作业计划列表 —— ObservableCollection<Wrap<ExecutionPlanInfo>> ExecutionPlans
        /// <summary>
        /// 作业计划列表
        /// </summary>
        [DependencyProperty]
        public ObservableCollection<Wrap<ExecutionPlanInfo>> ExecutionPlans { get; set; }
        #endregion

        #region 产品列表 —— ObservableCollection<MaterialInfo> Products
        /// <summary>
        /// 产品列表
        /// </summary>
        [DependencyProperty]
        public ObservableCollection<MaterialInfo> Products { get; set; }
        #endregion

        #region 工艺列表 —— ObservableCollection<ProcessInfo> Processes
        /// <summary>
        /// 工艺列表
        /// </summary>
        [DependencyProperty]
        public ObservableCollection<ProcessInfo> Processes { get; set; }
        #endregion

        #region 物料清单列表 —— ObservableCollection<BomInfo> Boms
        /// <summary>
        /// 物料清单列表
        /// </summary>
        [DependencyProperty]
        public ObservableCollection<BomInfo> Boms { get; set; }
        #endregion

        #region 计划状态字典 —— IDictionary<string, string> PlanStatuses
        /// <summary>
        /// 计划状态字典
        /// </summary>
        [DependencyProperty]
        public IDictionary<string, string> PlanStatuses { get; set; }
        #endregion

        #region 审核状态字典 —— IDictionary<string, string> CheckStatuses
        /// <summary>
        /// 审核状态字典
        /// </summary>
        [DependencyProperty]
        public IDictionary<string, string> CheckStatuses { get; set; }
        #endregion

        #endregion

        #region # 方法

        //Initializations

        #region 初始化 —— override async Task OnInitializeAsync(CancellationToken cancellationToken)
        /// <summary>
        /// 初始化
        /// </summary>
        protected override async Task OnInitializeAsync(CancellationToken cancellationToken)
        {
            IResourceContract resourceContract = this._resourceContract.Channel;
            IDefinitionContract definitionContract = this._definitionContract.Channel;

            IEnumerable<MaterialInfo> products = await Task.Run(() => resourceContract.GetMaterialsByPage(null, null, null, null, true, null, 1, int.MaxValue).Datas, cancellationToken);
            IEnumerable<ProcessInfo> processes = await Task.Run(() => definitionContract.GetProcessesByPage(null, null, null, null, true, CheckStatus.Passed, 1, int.MaxValue).Datas, cancellationToken);
            IEnumerable<BomInfo> bomInfos = await Task.Run(() => definitionContract.GetBomsByPage(null, null, null, true, CheckStatus.Passed, 1, int.MaxValue).Datas, cancellationToken);
            this.Products = new ObservableCollection<MaterialInfo>(products);
            this.Processes = new ObservableCollection<ProcessInfo>(processes);
            this.Boms = new ObservableCollection<BomInfo>(bomInfos);

            this.PlanStatuses = typeof(ExecutionPlanStatus).GetEnumMembers();
            this.CheckStatuses = typeof(CheckStatus).GetEnumMembers();

            await this.ReloadExecutionPlans();
        }
        #endregion


        //Actions

        #region 选择生产计划 —— async void SelectProductionPlan()
        /// <summary>
        /// 选择生产计划
        /// </summary>
        public async void SelectProductionPlan()
        {
            this.Busy();

            SelectProductionPlanViewModel viewModel = ResolveMediator.Resolve<SelectProductionPlanViewModel>();
            viewModel.Load(false, null, null);
            bool? result = await this._windowManager.ShowDialogAsync(viewModel);
            if (result == true)
            {
                Wrap<ProductionPlanInfo> wrapModel = viewModel.ProductionPlans.Single(x => x.IsChecked == true);
                this.SelectedProductionPlan = wrapModel.Model;
            }

            this.Idle();
        }
        #endregion

        #region 清空生产计划 —— void ClearProductionPlan()
        /// <summary>
        /// 清空生产计划
        /// </summary>
        public void ClearProductionPlan()
        {
            this.SelectedProductionPlan = null;
        }
        #endregion

        #region 选择工厂模型 —— async void SelectFacility()
        /// <summary>
        /// 选择工厂模型
        /// </summary>
        public async void SelectFacility()
        {
            this.Busy();

            SelectFacilityViewModel viewModel = ResolveMediator.Resolve<SelectFacilityViewModel>();
            bool? result = await this._windowManager.ShowDialogAsync(viewModel);
            if (result == true)
            {
                this.SelectedFacility = viewModel.SelectedFacility;
            }

            this.Idle();
        }
        #endregion

        #region 清空工厂模型 —— void ClearFacility()
        /// <summary>
        /// 清空工厂模型
        /// </summary>
        public void ClearFacility()
        {
            this.SelectedFacility = null;
        }
        #endregion

        #region 加载作业计划列表 —— async void LoadExecutionPlans()
        /// <summary>
        /// 加载作业计划列表
        /// </summary>
        public async void LoadExecutionPlans()
        {
            await this.ReloadExecutionPlans();
        }
        #endregion

        #region 跟踪生产计划 —— async void TrackExecutionPlan()
        /// <summary>
        /// 跟踪生产计划
        /// </summary>
        public async void TrackExecutionPlan()
        {
            #region # 验证

            if (this.ExecutionPlans.Count(x => x.IsChecked == true) != 1)
            {
                MessageBox.Show("请勾选一条要追溯的作业计划！", "警告", MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            #endregion

            Wrap<ExecutionPlanInfo> executionPlan = this.ExecutionPlans.Single(x => x.IsChecked == true);

            this.Busy();

            TrackViewModel viewModel = ResolveMediator.Resolve<TrackViewModel>();
            await viewModel.Load(executionPlan.Model);
            await this._windowManager.ShowDialogAsync(viewModel);

            this.Idle();
        }
        #endregion

        #region 全选 —— void CheckAll()
        /// <summary>
        /// 全选
        /// </summary>
        public void CheckAll()
        {
            this.ExecutionPlans.ForEach(x => x.IsChecked = true);
        }
        #endregion

        #region 取消全选 —— void UncheckAll()
        /// <summary>
        /// 取消全选
        /// </summary>
        public void UncheckAll()
        {
            this.ExecutionPlans.ForEach(x => x.IsChecked = false);
        }
        #endregion


        //Private

        #region 加载作业计划列表 —— async Task ReloadExecutionPlans()
        /// <summary>
        /// 加载作业计划列表
        /// </summary>
        private async Task ReloadExecutionPlans()
        {
            this.Busy();

            string keywords = this.Keywords;
            Guid? productId = this.SelectedProduct?.Id;
            Guid? processId = this.SelectedProcess?.Id;
            Guid? bomId = this.SelectedBom?.Id;
            Guid? productionPlanId = this.SelectedProductionPlan?.Id;
            ExecutionPlanStatus? planStatus = this.SelectedPlanStatus;
            CheckStatus? checkStatus = this.SelectedCheckStatus;
            DateTime? startTime = this.StartTime;
            DateTime? endTime = this.EndTime;
            Guid? facilityId = this.SelectedFacility?.Id;

            PageModel<ExecutionPlanInfo> pageModel = await Task.Run(() => this._planContract.Channel.GetExecutionPlansByPage(keywords, productId, processId, bomId, productionPlanId, planStatus, checkStatus, null, null, startTime, endTime, facilityId, this.PageIndex, this.PageSize));
            this.RowCount = pageModel.RowCount;
            this.PageCount = pageModel.PageCount;

            IEnumerable<Wrap<ExecutionPlanInfo>> wrapModels = pageModel.Datas.Select(x => x.Wrap());
            this.ExecutionPlans = new ObservableCollection<Wrap<ExecutionPlanInfo>>(wrapModels);

            this.Idle();
        }
        #endregion

        #endregion
    }
}
